﻿using ERP.Common.Util.Service;
using ERP.SYS.Config;
using ERP.SYS.Interfaces;
using ERP.SYS.Model.Entity;
using ERP.SYS.Model.VO;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace ERP.SYS.BLL;

public class RoleServiceImpl : BaseService<SysRole, ERPSysDbContext>, IRoleService
{
    private readonly ILogger<RoleServiceImpl> _logger;
    public RoleServiceImpl(IServiceScopeFactory serviceScopeFactory, ILogger<RoleServiceImpl> logger) : base(serviceScopeFactory)
    {
        _logger = logger;
    }

    public List<SysRolePermission> GetRolePermissions()
    {
        using (var scope = _serviceScopeFactory.CreateScope())
        {
            using (var context = scope.ServiceProvider.GetRequiredService<ERPSysDbContext>())
            {
                var query = from r in context.SysRoles
                            join rp in context.SysRolePermissions on r.RoleId equals rp.RoleId
                            join p in context.SysPermissions on rp.PermissionId equals p.PermissionId
                            where r.IsDelete == 0 && p.IsDelete == 0 && p.IsUse == 0
                            select new SysRolePermission
                            {
                                RoleId = rp.RoleId,
                                PermissionId = rp.PermissionId,
                                Permission = new SysPermission
                                {
                                    PermissionId = p.PermissionId,
                                    Path = p.Path,
                                    IsUse = p.IsUse,
                                    IsDelete = p.IsDelete
                                },
                                Role = r
                            };
                return query.ToList();
            }
        }
    }

    public async Task<List<MenuVO>> LoadMenuByRoleId(int roleId)
    {
        List<SysMenu> menus = new List<SysMenu>();
        List<MenuVO> menusVOs = new List<MenuVO>();
        Dictionary<long, MenuVO> menuPairs = new Dictionary<long, MenuVO>();

        using (var scope = _serviceScopeFactory.CreateScope())
        {
            using (var context = scope.ServiceProvider.GetRequiredService<ERPSysDbContext>())
            {
                var query = from r in context.SysRoles
                            join rm in context.SysRoleMenus on r.RoleId equals rm.RoleId
                            join m in context.SysMenus on rm.MenuId equals m.MenuId
                            where r.IsDelete == 0 && m.IsDelete == 0 && r.RoleId == roleId && m.Status == 0
                            orderby m.ParentId, m.MenuId
                            select new SysMenu
                            {
                                MenuId = rm.MenuId,
                                ParentId = m.ParentId,
                                Name = m.Name,
                                Url = m.Url,
                                Status = m.Status,
                                CreateAt = m.CreateAt,
                                UpdateAt = m.UpdateAt
                            };
                menus = await query.ToListAsync();
            }
        }

        foreach (SysMenu menu in menus)
        {
            // if can get it parent MenuVO
            // make it in to it parent ChildrenMenu
            menuPairs.TryGetValue(menu.ParentId, out var tempMenu);

            MenuVO menuVO = new MenuVO
            {
                Menu = menu,
                ChildernMenu = new List<MenuVO>()
            };

            menuPairs.Add(menu.MenuId, menuVO);

            // if tempMenu is null 
            // represents this menu is the top menu
            if (tempMenu == null)
            {
                menusVOs.Add(menuVO);
                continue;
            }

            tempMenu.ChildernMenu.Add(menuVO);
        }

        return menusVOs;
    }

    public async Task<SysRoleUser> SelectUserRoleByNameAndPassword(string username, string password)
    {
        using (var scope = _serviceScopeFactory.CreateScope())
        {
            using (var context = scope.ServiceProvider.GetRequiredService<ERPSysDbContext>())
            {
                var query = from r in context.SysRoles
                            join ru in context.SysRoleUsers on r.RoleId equals ru.RoleId
                            join u in context.SysUsers on ru.UserId equals u.UserId
                            where r.IsDelete == 0 && u.IsDelete == 0 && u.Name == username && u.Password == password
                            select new SysRoleUser
                            {
                                RoleId = ru.RoleId,
                                UserId = ru.UserId,
                                User = u,
                                Role = r
                            };
                return await query.FirstAsync();
            }
        }
    }
}
